'''
 * CaRComp Execution Environment
 * 
 * Copyright (C) 2011 Taylor L. Riche
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
'''

from carcomp.framework import application, component
from carcomp.framework.file_io import *
from carcomp.framework.net_io import *
from carcomp.directory import cameras
import optparse, time
from carcomp.apps.ft.client import translator
from carcomp.apps.ft.messages import client_msgs
from carcomp.framework.quorum import gen_quorum

class EchoClientComp(component.Implementation):
    
    def __init__(self, name, node_name):
        component.Implementation.__init__(self, name)
        self._node_name = node_name
    
    def gen_requests(self, msg):
        print('Sending to server: ', msg);
        message = client_msgs.Message()
        message.create_msg_body(self._node_name, round(time.time()), msg) 
        self.send_out('server_out', (cameras.SERVER_NAME, message.get_body()))        
    
    def process_server_response(self, msg):
        message = client_msgs.Message(msg)
        print("Got this from server: " + message.get_body())
        if message._node_name != self._node_name:
            print('Server sent to wrong client')
        self.send_out('log_response', message.content)
        
class EchoClient(application.Application):
    '''
    ACFT Client application
    '''
    
    def __init__(self):
        application.Application.__init__(self)
        self.__infile__ = ''
        self.__outfile__ = ''
        
    def setup(self):

        translator_comp = translator.Translator('translator_comp')
        self.create_component(translator_comp, [('msg_in', 'trans_out'), ('net_out', '__OUT__')])

        echo_comp = EchoClientComp('echo_comp', self._node_name)
        self.create_component(echo_comp, [('gen_port', 'gen_requests'), ('server_in', 'process_server_response'),
                                           ('server_out', '__OUT__'), ('log_response', '__OUT__')])

        q_comp = gen_quorum.GenericQuorum('q_comp', cameras.local_directory.server_q_thresh)
        self.create_component(q_comp, [('in', 'process_msg'), ('q_found', '__OUT__')])

        fr = file_reader.FileReaderComponent(self.__infile__)
        fw = file_writer.FileWriterComponent(self.__outfile__)
        nr = net_reader.NetReaderComponent(self._node_name, cameras.local_directory)
        nw = net_writer.NetWriterComponent('netwriter', self._node_name, cameras.local_directory)

        self.add_components([fr, fw, nr, nw])

        fr_to_echo = self.create_connection(('filereader', 'out'), ('echo_comp', 'gen_port'))

        echo_to_trans = self.create_connection(('echo_comp', 'server_out'), ('translator_comp', 'msg_in'))
        trans_to_nw = self.create_connection(('translator_comp', 'net_out'), ('netwriter', 'in'))
        echo_to_fw = self.create_connection(('echo_comp', 'log_response'), ('filewriter', 'in'))
        nr_to_q = self.create_connection((self._node_name, 'out'), ('q_comp', 'in'))
        q_to_echo = self.create_connection(('q_comp', 'q_found'), ('echo_comp', 'server_in'))
        #nr_to_echo = self.create_connection((self._node_name, 'out'), ('echo_comp', 'server_in'))
        
        self.add_connections([fr_to_echo, echo_to_fw, nr_to_q, q_to_echo, trans_to_nw])        


        nr_thread = application.CompThread(nr, [nr_to_q], True)
        nw_thread = application.CompThread(nw, [trans_to_nw])
        fr_thread = application.CompThread(fr, [fr_to_echo], True)
        fw_thread = application.CompThread(fw, [echo_to_fw])
        echo_thread = application.CompThread(echo_comp, [q_to_echo, fr_to_echo, echo_to_fw, echo_to_trans])
        trans_thread = application.CompThread(translator_comp, [echo_to_trans, trans_to_nw])
        q_thread = application.CompThread(q_comp, [nr_to_q, q_to_echo])

        self.add_threads([nr_thread, nw_thread, fr_thread, fw_thread, echo_thread, q_thread])
        # SCFT1
        self.add_thread(trans_thread)
        # //

    def parse_opts(self):
        usage = 'usage: %prog [opts] NODE_NAME'
        parser = optparse.OptionParser(usage)
        parser.add_option("-i", "--input", dest="input_file", help="read data from FILENAME", default='INSTREAM.txt')
        parser.add_option("-o", "--output", dest="output_file", help="store data in FILENAME", default='OUTSTREAM.txt')
        (opts, args) = parser.parse_args()
        if(len(args) == 0):
            parser.error('Please specify a NODE_NAME')
        elif(len(args) > 1):
            parser.error('Improper argument list, please only specify one NODE_NAME')
        else:
            self.handle_name(args[0])
        self.__infile__ = opts.input_file
        self.__outfile__ = opts.output_file
        

if __name__ == "__main__":
    client = EchoClient()
    client.parse_opts()
    client.setup()    
    client.execute()
